﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Collections;

using LuaInterface;
using BackgroundTest.BasicAbstracts;

namespace BackgroundTest.LogicInterface
{
    public class AttrLuaFunc : Attribute
    {
        private String FunctionName;
        private String FunctionDoc;
        private String[] FunctionParameters = null;

        public AttrLuaFunc(String strFuncName, String strFuncDoc, params String[] strParamDocs)
        {
            FunctionName = strFuncName;
            FunctionDoc = strFuncDoc;
            FunctionParameters = strParamDocs;
        }

        public AttrLuaFunc(String strFuncName, String strFuncDoc)
        {
            FunctionName = strFuncName;
            FunctionDoc = strFuncDoc;
        }

        public String getFuncName()
        {
            return FunctionName;
        }

        public String getFuncDoc()
        {
            return FunctionDoc;
        }

        public String[] getFuncParams()
        {
            return FunctionParameters;
        }
    }

    public class LuaFuncDescriptor
    {
        private String FunctionName;
        private String FunctionDoc;
        private ArrayList FunctionParameters;
        private ArrayList FunctionParamDocs;
        private String FunctionDocString;

        public LuaFuncDescriptor(String strFuncName, String strFuncDoc, ArrayList strParams,
                                                         ArrayList strParamDocs)
        {
            FunctionName = strFuncName;
            FunctionDoc = strFuncDoc;
            FunctionParameters = strParams;
            FunctionParamDocs = strParamDocs;

            String strFuncHeader = strFuncName + "(%params%) - " + strFuncDoc;
            String strFuncBody = "\n\n";
            String strFuncParams = "";

            Boolean bFirst = true;

            for (int i = 0; i < strParams.Count; i++)
            {
                if (!bFirst)
                    strFuncParams += ", ";

                strFuncParams += strParams[i];
                strFuncBody += "\t" + strParams[i] + "\t\t" + strParamDocs[i] + "\n";

                bFirst = false;
            }

            strFuncBody = strFuncBody.Substring(0, strFuncBody.Length - 1);
            if (bFirst)
                strFuncBody = strFuncBody.Substring(0, strFuncBody.Length - 1);

            FunctionDocString = strFuncHeader.Replace("%params%", strFuncParams) + strFuncBody;
        }

        public String getFuncName()
        {
            return FunctionName;
        }

        public String getFuncDoc()
        {
            return FunctionDoc;
        }

        public ArrayList getFuncParams()
        {
            return FunctionParameters;
        }

        public ArrayList getFuncParamDocs()
        {
            return FunctionParamDocs;
        }

        public String getFuncHeader()
        {
            if (FunctionDocString.IndexOf("\n") == -1)
                return FunctionDocString;

            return FunctionDocString.Substring(0, FunctionDocString.IndexOf("\n"));
        }

        public String getFuncFullDoc()
        {
            return FunctionDocString;
        }
    }

    class LuaFramework
    {
        private static LuaFramework instance;

        public static LuaFramework Instance
        {
            get
            {
                if (null == instance)
                {
                    instance = new LuaFramework();
                }
                return instance;
            }
        }

        // The Lua virtual machine used in logic process:
        private Lua luaLogicVM;
        public Lua LuaLogicVM
        {
            get { return luaLogicVM; }
        }

        private Hashtable luaLogicFuncts;

        private LuaFramework()
        {
            luaLogicVM = new Lua();
            luaLogicFuncts = new Hashtable(); 
        }

        public void registerLuaFunctions(Object pTarget)
        {
            // Sanity checks 
            if (luaLogicVM == null || luaLogicFuncts == null)
                return;

            // Get the target type 
            Type pTrgType = pTarget.GetType();

            // ... and simply iterate through all it's methods 
            foreach (MethodInfo mInfo in pTrgType.GetMethods())
            {
                // ... then through all this method's attributes 
                foreach (Attribute attr in Attribute.GetCustomAttributes(mInfo))
                {
                    // and if they happen to be one of our AttrLuaFunc attributes 
                    if (attr.GetType() == typeof(AttrLuaFunc))
                    {//这样的判断较为严谨杜绝了,属性基类的标注的时候,不一样的描述 
                        AttrLuaFunc pAttr = (AttrLuaFunc)attr;
                        Hashtable pParams = new Hashtable();

                        // Get the desired function name and doc string, along with parameter info 
                        String strFName = pAttr.getFuncName();//获取属性中描述的 函数名 
                        String strFDoc = pAttr.getFuncDoc();//函数描述 
                        String[] pPrmDocs = pAttr.getFuncParams();//参数描述 

                        // Now get the expected parameters from the MethodInfo object 
                        ParameterInfo[] pPrmInfo = mInfo.GetParameters();//参数表 

                        // If they don't match, someone forgot to add some documentation to the  
                        // attribute, complain and go to the next method 
                        if (pPrmDocs != null && (pPrmInfo.Length != pPrmDocs.Length))
                        {
                            Console.WriteLine("Function " + mInfo.Name + " (exported as " +
                                              strFName + ") argument number mismatch. Declared " +
                                              pPrmDocs.Length + " but requires " +
                                              pPrmInfo.Length + ".");
                            break;
                        }
                        ArrayList paras = new ArrayList();
                        ArrayList paradocs = new ArrayList();
                        // Build a parameter <-> parameter doc hashtable 
                        for (int i = 0; i < pPrmInfo.Length; i++)
                        {
                            pParams.Add(pPrmInfo[i].Name, pPrmDocs[i]);
                            paras.Add(pPrmInfo[i].Name);
                            paradocs.Add(pPrmDocs[i]);
                        }


                        // Get a new function descriptor from this information 
                        //LuaFuncDescriptor pDesc = new LuaFuncDescriptor(strFName, strFDoc, pParams, pPrmDocs); 
                        LuaFuncDescriptor pDesc = new LuaFuncDescriptor(strFName, strFDoc, paras, paradocs);

                        // Add it to the global hashtable 
                        luaLogicFuncts.Add(strFName, pDesc);

                        // And tell the VM to register it. 
                        luaLogicVM.RegisterFunction(strFName, pTarget, mInfo);                       
                        //  pLuaVM.RegisterFunction(strFName+1, pTarget, mInfo); 
                        //说明注册函数的时候,函数名并不重要,只要mInfo正确即可,就会将一个函数名指向他 
                        // 这么多工作也只是为了 获取想要的函数名而已,并不是必须的, 
                        // 这样的有利于自动注册函数,而不用手动. 
                        // 代码想要修改才能使用 
                    }
                }
            }
        }
    }
}
